//==============================================================================
//
//          DUDPServer - the udp server class in the ofc-library
//
//               Copyright (C) 2004  Dick van Oudheusden
//  
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2006-07-22 13:28:57 $ $Revision: 1.9 $

//==============================================================================

#include <stdlib.h>
#include <unistd.h>

#include "ofc/DUDPServer.h"


#if _INTERFACE_

#include "ofc/config.h"

#include "ofc/DSocketAddress.h"
#include "ofc/DSocket.h"


//
// The DUDPServer class implements a number of methods for implementing a UDP server.
// (Note: this class assumes that the socket is blocking)
//

@interface DUDPServer : Object
{
@private
  DSocket                *_local;       // the local socket
  int                     _sendFlag;    // the send flag (def. 0)
  int                     _recvFlag;    // the receive flag (def. 0)
  unsigned                _recvLength;  // the length used during receiving of requests (def. 1024)
  id <DSocketAddressable> _peer;        // the peer address
}

#endif


@implementation DUDPServer


//// Constructors

//
// Initialise the UDP Server
//
// @return the object
//

- (DUDPServer *) init
{
  [super init];

  _local       = [DSocket new];
  _sendFlag    = 0;
  _recvFlag    = 0;
  _recvLength  = 1024;
  
  return self;
}

//
// Initialise the UDP Server for a family and protocol
//
// @param family       the family (DSA_AF_INET, DSA_AF_UNIX, DSA_AF_INET6)
// @param protocol     the protocol to be used
// 
// @return the object
//

- (DUDPServer *) init :(int) family :(int) protocol
{
  [self init];
  
  [self open :family :protocol];
  
  return self;
}


//// Copy related methods

//
// Do a shallow copy of the object (not implemented)
//
// @return the object
//
- shallowCopy
{
  WARNING(DW_METHOD_NOT_IMPL, "shallowCopy");
  
  return [super shallowCopy];
}


//// Deconstructor

//
// Free the UDP server object
//
// @return the object
//

- free
{
  [_local free];
  
  return [super free];
}


//// Member methods

//
// Return the local socket for the UDP server
// 
// @return a reference to the local socket 
//

- (DSocket *) socket
{
  return _local;
}

//
// Set the send flag
// 
// @param flag         the send flag
// 
// @return the object
// 

- (DUDPServer *) sendFlag :(int) flag
{
  _sendFlag = flag;
  
  return self;
}

//
// Return the send flag
// 
// @return the send flag
// 

- (int) sendFlag
{
  return _sendFlag;
}

//
// Set the receive flag
// 
// @param flag         the receive flag
// 
// @return the object
// 

- (DUDPServer *) recvFlag :(int) flag
{
  _recvFlag = flag;
  
  return self;
}

//
// Return the receive flag
// 
// @return the receive flag
// 

- (int) recvFlag
{
  return _recvFlag;
}

//
// Set the length for receiving of requests
// 
// @param length       the length
// 
// @return the object
// 

- (DUDPServer *) recvLength :(unsigned) length
{
  if (length > 0)
  {
    _recvLength = length;
  }
  else
  {
    WARNING(DW_INVALID_ARG, "length");
  }
  
  return self;
}

//
// Return the length for receiving of requests
// 
// @return the length
// 

- (unsigned) recvLength
{
  return _recvLength;
}


//// Main methods

//
// Open the UDP server
// 
// @param family       the family (DSA_AF_INET, DSA_AF_UNIX, DSA_AF_INET6)
// @param protocol     the protocol to be used
// 
// @return success
// 

- (BOOL) open :(int) family :(int) protocol
{
  BOOL ok = NO;

  if ([_local open :family :DSK_DGRAM :protocol])
  {
    ok = YES;
  }
  
  return ok;
}
      
//
// Start the handling of requests (blocking, loop until error or stop request)
//
// @return the object
//

- (BOOL) start :(id <DSocketAddressable>) address
{
  BOOL ok = NO;

  if ([_local bind :address])
  {
    BOOL stopRequest = NO;

    id <DSocketAddressable> peer = [address copy];
    
    ok = YES;
    
    while ((ok) && (!stopRequest))
    {
      DData *sendMsg = [DData new];
      DData *recvMsg = nil;
      
      recvMsg = [_local recvfrom :peer :_recvLength :_recvFlag];
    
      if (recvMsg != nil)
      {
        [sendMsg clear];
        
        stopRequest = [self handleRequest :recvMsg :sendMsg];
      
        if ([sendMsg length] > 0)
        {
          ok = ([_local sendto :peer :(void *)[sendMsg data] :[sendMsg length] :_sendFlag] >= 0);
        }
      
        [recvMsg free];
      }
      else
      {
        ok = NO;
      }
    }

    [_local close];
    
    [peer free];
  }
  
  return ok;
}

//
// Handle a new request by the client (called by handleRequests, to be overridden)
// 
// @param request      the request made by the client
// @param respone      the destination for the response
// 
// @return should the server be stopped ?
//

- (BOOL) handleRequest :(DData *) request :(DData *) response
{
  return YES; 
}

@end

/*===========================================================================*/

